package com.xiaoyu.util2;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import de.idyl.winzipaes.AesZipFileDecrypter;
import de.idyl.winzipaes.AesZipFileEncrypter;
import de.idyl.winzipaes.impl.AESDecrypterBC;
import de.idyl.winzipaes.impl.AESEncrypterBC;
import de.idyl.winzipaes.impl.ExtZipEntry;

public class ZIPUtil {
	public static void deCompress(File file, String dest) throws Exception {
		ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
		zipFile(file, zos, "");
		zos.close();
	}

	public static void zipFile(File inFile, ZipOutputStream zos, String dir)
			throws IOException {
		if (inFile.isDirectory()) {
			File[] files = inFile.listFiles();
			for (File file : files) {
				String name = inFile.getName();
				if (!("".equals(dir))) {
					name = dir + "/" + name;
				}
				zipFile(file, zos, name);
			}
		} else {
			String entryName = null;
			if (!("".equals(dir)))
				entryName = dir + "/" + inFile.getName();
			else {
				entryName = inFile.getName();
			}
			ZipEntry entry = new ZipEntry(entryName);
			zos.putNextEntry(entry);
			InputStream is = new FileInputStream(inFile);
			int len = 0;
			while ((len = is.read()) != -1) {
				zos.write(len);
			}
			is.close();
		}
	}

	public static void unCompress(File source, String path) throws IOException {
		ZipFile zipFile = new ZipFile(source);
		ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(source));
		ZipEntry zipEntry = null;
		FileUtil.createPaths(path);
		while ((zipEntry = zipInputStream.getNextEntry()) != null) {
			String fileName = zipEntry.getName();
			File temp = new File(path + "/" + fileName);
			if (!(temp.getParentFile().exists())) {
				temp.getParentFile().mkdirs();
			}
			OutputStream os = new FileOutputStream(temp);
			InputStream is = zipFile.getInputStream(zipEntry);
			int len = 0;
			while ((len = is.read()) != -1)
				os.write(len);
			os.close();
			is.close();
		}
		zipInputStream.close();
	}
	
	//========第二种
	public Boolean compress(String inFile, String outFile, String key) throws Exception {
		Boolean flag = false;
		ArrayList<String> fileList = new ArrayList<String>();
		fileList.add(inFile);
		compress(fileList, outFile, key);
		flag = true;
		return flag;
	}

	public Boolean compress(List<String> inFiles, String outFile, String key) throws Exception {
		Boolean flag = false;
		String tempFile = outFile;
		if (null != key && !"".equals(key)) {
			tempFile = tempFile + "temp";
		}
		ArrayList<String> filePathList = new ArrayList<String>();
		ArrayList<String> fileNameList = new ArrayList<String>();
		if (inFiles != null && inFiles.size() > 0) {
			File file = null;
			for (String fileStr : inFiles) {
				file = new File(fileStr);
				filePathList.add(file.getAbsolutePath());
				fileNameList.add(file.getName());
			}
			makeZip(filePathList, fileNameList, tempFile);
			if (null != key && !"".equals(key)) {
				File temp = new File(tempFile);
				AesZipFileEncrypter enc = new AesZipFileEncrypter(outFile, new AESEncrypterBC());
				enc.addAll(temp, key);
				enc.close();
				temp.delete();
			}
		}
		flag = true;
		return flag;
	}

	public Boolean compress(String inDir, String outFile, String key, Boolean ifSubDir) throws Exception {
		System.out.println("--inDir--" + inDir);
		System.out.println("--outFile--" + outFile);
		Boolean flag = false;
		String tempFile = outFile;
		if (null != key && !"".equals(key)) {
			tempFile = tempFile + "temp";
		}
		makeZip(new File(inDir), tempFile, ifSubDir);
		if (null != key && !"".equals(key)) {
			File temp = new File(tempFile);
			AesZipFileEncrypter enc = new AesZipFileEncrypter(outFile, new AESEncrypterBC());
			enc.addAll(temp, key);
			enc.close();
			temp.delete();
		}
		flag = true;
		return flag;
	}

	public Boolean uncompress(String inFile, String outDir, String key, Boolean ifSubDir) throws Exception {
		boolean flag = false;
		if (key == null || "".equals(key)) {
			unZip(inFile, new File(outDir));
		} else {
			AesZipFileDecrypter zipFile = new AesZipFileDecrypter(new File(inFile), new AESDecrypterBC());
			for (ExtZipEntry entry : zipFile.getEntryList()) {
				if (!ifSubDir) {
					String filename = entry.getName();
					String[] strArray = filename.split(File.separator + File.separator);
					if (strArray != null && strArray.length == 1) {
						zipFile.extractEntry(entry, new File(outDir + File.separator + entry.getName()), key);
					}
				} else {
					zipFile.extractEntry(entry, new File(outDir + File.separator + entry.getName()), key);
				}
			}
		}
		flag = true;
		return flag;
	}

	@SuppressWarnings("rawtypes")
	private void unZip(String zipFilePath, File toUnzipFold) throws IOException {
		if (!toUnzipFold.exists()) {
			toUnzipFold.mkdirs();
		}
		ZipFile zfile = new ZipFile(zipFilePath);
		// zList包含了所有的文件夹、目录信息
		Enumeration zList = zfile.entries();
		byte[] buf = new byte[1024];
		File tmpfile = null;
		File tmpfold = null;
		while (zList.hasMoreElements()) {
			ZipEntry ze = (ZipEntry) zList.nextElement();
			tmpfile = new File(toUnzipFold.getAbsolutePath() + File.separator + ze.getName());
			if (ze.isDirectory()) {
				continue;
			} else {
				tmpfold = tmpfile.getParentFile();
				if (!tmpfold.exists()) {
					tmpfold.mkdirs();
				}
				OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpfile.getAbsolutePath()));
				InputStream is = new BufferedInputStream(zfile.getInputStream(ze));
				int readLen = 0;
				while ((readLen = is.read(buf, 0, 1024)) != -1) {
					os.write(buf, 0, readLen);
				}
				is.close();
				os.close();
			}
		}
	}

	@SuppressWarnings("unused")
	private void makeZip(File fold, String outputZipFileName) throws IOException {
		makeZip(fold, outputZipFileName, false);
	}

	private void makeZip(File fold, String outputZipFileName, boolean recursive) throws IOException {
		if (fold.exists()) {
			ArrayList<File> fileList = new ArrayList<File>();
			listAllFile(fold, fileList, recursive);
			ArrayList<String> filePathList = new ArrayList<String>();
			ArrayList<String> fileNameList = new ArrayList<String>();
			String tmpStr = null;
			int basLen = fold.getAbsolutePath().length();
			for (File f : fileList) {
				tmpStr = f.getAbsolutePath();
				filePathList.add(tmpStr);
				fileNameList.add(tmpStr.substring(basLen + 1, tmpStr.length()));
			}
			makeZip(filePathList, fileNameList, outputZipFileName);
		}
	}

	private void listAllFile(File fold, ArrayList<File> fileList, boolean recursive) {
		File[] files = fold.listFiles();
		for (File f : files) {
			if (recursive && f.isDirectory()) {
				listAllFile(f, fileList, recursive);
			} else if (!f.isDirectory()) {
				fileList.add(f);
			}
		}
	}

	private void makeZip(ArrayList<String> filePathList, ArrayList<String> fileNameList, String outputZipFileName) throws IOException {
		byte[] buf = new byte[1024];
		File outputZipFile = new File(outputZipFileName);
		File outputZipParentFile = outputZipFile.getParentFile();
		if (!outputZipParentFile.exists()) {
			outputZipParentFile.mkdirs();
		}
		ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outputZipFile));
		int len = -1;
		for (int i = 0; i < filePathList.size(); i++) {
			if (filePathList.get(i) != null) {
				FileInputStream in = new FileInputStream(filePathList.get(i));
				out.putNextEntry(new org.apache.tools.zip.ZipEntry(CharsetUtil.toUTF_8(fileNameList.get(i))));
				while ((len = in.read(buf)) > 0) {
					out.write(buf, 0, len);
				}
				out.closeEntry();
				in.close();
			}
		}
		out.close();
	}
	
	//=================第三种
	public static java.util.List<File> getFileList(String zipFileString, boolean bContainFolder, boolean bContainFile) throws Exception {
		System.out.println("GetFileList(String)");
		java.util.List<File> fileList = new java.util.ArrayList<File>();
		java.util.zip.ZipInputStream inZip = new java.util.zip.ZipInputStream(new java.io.FileInputStream(zipFileString));
		java.util.zip.ZipEntry zipEntry;
		String szName = "";
		while ((zipEntry = inZip.getNextEntry()) != null) {
			szName = zipEntry.getName();
			if (zipEntry.isDirectory()) {
				// get the folder name of the widget
				szName = szName.substring(0, szName.length() - 1);
				java.io.File folder = new java.io.File(szName);
				if (bContainFolder) {
					fileList.add(folder);
				}
			} else {
				java.io.File file = new java.io.File(szName);
				if (bContainFile) {
					fileList.add(file);
				}
			}
		}// end of while
		inZip.close();
		return fileList;
	}

	public static java.io.InputStream upZip(String zipFileString, String fileString) throws Exception {
		System.out.println("UpZip(String, String)");
		java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(zipFileString);
		java.util.zip.ZipEntry zipEntry = zipFile.getEntry(fileString);
		return zipFile.getInputStream(zipEntry);
	}

	public static void unZipFolder(String zipFileString, String outPathString) throws Exception {
		System.out.println("UnZipFolder(String, String)");
		java.util.zip.ZipInputStream inZip = new java.util.zip.ZipInputStream(new java.io.FileInputStream(zipFileString));
		java.util.zip.ZipEntry zipEntry;
		String szName = "";
		while ((zipEntry = inZip.getNextEntry()) != null) {
			szName = zipEntry.getName();
			szName = szName.replaceAll("\\\\", "/");
			if (zipEntry.isDirectory()) {
				// get the folder name of the widget
				szName = szName.substring(0, szName.length() - 1);
				java.io.File folder = new java.io.File(outPathString + java.io.File.separator + szName);
				folder.mkdirs();
			} else {
				java.io.File file = new java.io.File(outPathString + java.io.File.separator + szName);
				file.createNewFile();
				// get the output stream of the file
				java.io.FileOutputStream out = new java.io.FileOutputStream(file);
				int len;
				byte[] buffer = new byte[1024];
				// read (len) bytes into buffer
				while ((len = inZip.read(buffer)) != -1) {
					// write (len) byte from buffer at the position 0
					out.write(buffer, 0, len);
					out.flush();
				}
				out.close();
			}
		}// end of while
		inZip.close();
	}// end of func

	public static void ZipFolder(String srcFileString, String zipFileString) throws Exception {
		System.out.println("ZipFiles(String, String)");
		// 创建Zip包
		java.util.zip.ZipOutputStream outZip = new java.util.zip.ZipOutputStream(new java.io.FileOutputStream(zipFileString));
		// 打开要输出的文件
		java.io.File file = new java.io.File(srcFileString);
		// 压缩
		ZipFiles(file.getParent() + java.io.File.separator, file.getName(), outZip);
		// 完成,关闭
		outZip.finish();
		outZip.close();
	}// end of func

	private static void ZipFiles(String folderString, String fileString, java.util.zip.ZipOutputStream zipOutputSteam) throws Exception {
		System.out.println("ZipFiles(String, String, ZipOutputStream)");
		if (zipOutputSteam == null)
			return;
		java.io.File file = new java.io.File(folderString + fileString);
		// 判断是不是文件
		if (file.isFile()) {
			java.util.zip.ZipEntry zipEntry = new java.util.zip.ZipEntry(fileString);
			java.io.FileInputStream inputStream = new java.io.FileInputStream(file);
			zipOutputSteam.putNextEntry(zipEntry);
			int len;
			byte[] buffer = new byte[4096];
			while ((len = inputStream.read(buffer)) != -1) {
				zipOutputSteam.write(buffer, 0, len);
			}
			zipOutputSteam.closeEntry();
		} else {
			// 文件夹的方式,获取文件夹下的子文件
			String fileList[] = file.list();
			// 如果没有子文件, 则添加进去即可
			if (fileList.length <= 0) {
				java.util.zip.ZipEntry zipEntry = new java.util.zip.ZipEntry(fileString + java.io.File.separator);
				zipOutputSteam.putNextEntry(zipEntry);
				zipOutputSteam.closeEntry();
			}
			// 如果有子文件, 遍历子文件
			for (int i = 0; i < fileList.length; i++) {
				ZipFiles(folderString, fileString + java.io.File.separator
						+ fileList[i], zipOutputSteam);
			}// end of for
		}// end of if
	}// end of func

	public static void main(String args[]) throws Exception {
		ZIPUtil z = new ZIPUtil();
		// 压缩
//		 z.compress("C:/ZipTest/a.xlsx", "C:/ZipTest/a.zip", "123");
		// z.compress("f:/testk", "f:/testsub.zip", "",true);//无密码，有子目录
//		z.compress("f:/testk", "f:/ttt/tttttt/tt/testsubk.zip", "123", true);// 有密码，有子目录
		// z.compress("f:/testk", "f:/test.zip", "",false);//无密码，无子目录
		// z.compress("f:/testk", "f:/testk.zip", "123",false);//无密码，无子目录
		// 解压
//		 z.uncompress("C:/ZipTest/a.zip", "C:/ZipTest/","",true);
		 z.uncompress("C:/ZipTest/a.zip", "C:/ZipTest/","123",true);
		// z.uncompress("f:/test.zip", "f:/test","",false);
		// z.uncompress("f:/testk.zip", "f:/testkk","123",false);
	}
}